﻿#include <core\SkShader.h>
#include <core\SkDevice.h>
#include <core/SkGraphics.h>
#include <effects\SkDashPathEffect.h>
#include <effects\SkGradientShader.h>
#include <effects\SkBlurMaskFilter.h>
#include "../skia/src/effects/SkBlurMask.h"
#include "../render/gdialpha.h"
#include "drawtext-skia.h"
#include "render-skia.h"

#include "skia2rop2.h"
#include "PathEffect-Skia.h"
#include "PathMeasure-Skia.h"

#include <tchar.h>
#include <algorithm>
#include <assert.h>
#include <vector>
#include <map>
#include <string>

#define getTotalClip internal_private_getTotalClip
// #include <vld.h>

#ifndef PI	//PI
#define PI         ((float)3.141592654f)
#endif

namespace SOUI
{
	//PS_SOLID
	const float  ps_solid[] ={1.0f,0.0f};
	const float  ps_dash[] ={5.0f,5.0f};
	const float  ps_dot[] ={1.0f,4.0f};
	const float  ps_dashdot[] ={4.0f,1.0f,1.0f,1.0f};
	const float  ps_dashdotdot[] ={4.0f,1.0f,1.0f,1.0f,1.0f,1.0f};

	const struct LineDashEffect
	{
		const float  *fDash;
		int		nCount;
	}LINEDASHEFFECT[] =
	{
		{ps_solid,ARRAYSIZE(ps_solid)},
		{ps_dash,ARRAYSIZE(ps_dash)},
		{ps_dot,ARRAYSIZE(ps_dot)},
		{ps_dashdot,ARRAYSIZE(ps_dashdot)},
		{ps_dashdotdot,ARRAYSIZE(ps_dashdotdot)},
	};

	bool String2Bool(const std::wstring & value)
	{
		assert(!value.empty());
		return !(value == L"false" || value == L"0");
	}

    SkIRect toSkIRect(LPCRECT pRc)
    {
        SkIRect rc={pRc->left,pRc->top,pRc->right,pRc->bottom};
        return rc;
    }

    SkRect toSkRect(LPCRECT pRc)
    {
        SkIRect rc={pRc->left,pRc->top,pRc->right,pRc->bottom};
        return SkRect::Make(rc);
    }
    
	void SkRect2RECT(const SkRect & rcIn, RECT * rcOut)
	{
		rcOut->left = (int)rcIn.fLeft;
		rcOut->top = (int)rcIn.fTop;
		rcOut->right = (int)(rcIn.fRight + 0.5f);
		rcOut->bottom = (int)(rcIn.fBottom + 0.5f);
	}

    void InflateSkRect(SkRect *pRect,SkScalar dx,SkScalar dy)
    {
        pRect->fLeft -= dx;
        pRect->fRight += dx;
        pRect->fTop -= dy;
        pRect->fBottom += dy;
    }
    
    int RectWid(LPCRECT pRc){return pRc->right-pRc->left;}
    int RectHei(LPCRECT pRc){return pRc->bottom-pRc->top;}
    
#define PS_ENDCAP_ROUND     0x00000000
#define PS_ENDCAP_SQUARE    0x00000100
#define PS_ENDCAP_FLAT      0x00000200
#define PS_ENDCAP_MASK      0x00000F00

#define PS_JOIN_ROUND       0x00000000
#define PS_JOIN_BEVEL       0x00001000
#define PS_JOIN_MITER       0x00002000
#define PS_JOIN_MASK        0x0000F000

#define PS_COSMETIC         0x00000000
#define PS_GEOMETRIC        0x00010000
#define PS_TYPE_MASK        0x000F0000

	class SLineDashEffect
	{
	public:
		SLineDashEffect(int iStyle):pDashPathEffect(NULL)
		{
			iStyle = iStyle&PS_STYLE_MASK;
			if(iStyle>=PS_SOLID && iStyle<=PS_DASHDOTDOT)
			{
				const LineDashEffect *pEff=&LINEDASHEFFECT[iStyle];
				pDashPathEffect=SkDashPathEffect::Create(pEff->fDash,pEff->nCount,0.0f);
			}
		}
		~SLineDashEffect()
		{
			if(pDashPathEffect) pDashPathEffect->unref();
		}

		SkDashPathEffect * Get() const{return pDashPathEffect;}
	private:
		SkDashPathEffect * pDashPathEffect;
	};

	class SStrokeCap{
	public:
		SStrokeCap(int iStyle){
			iStyle = iStyle & PS_ENDCAP_MASK;
			switch(iStyle)
			{
			case PS_ENDCAP_ROUND: m_Cap = SkPaint::kRound_Cap;break;
			case PS_ENDCAP_SQUARE: m_Cap = SkPaint::kSquare_Cap;break;
			case PS_ENDCAP_FLAT:default: m_Cap = SkPaint::kDefault_Cap; break;
			}
		}

		SkPaint::Cap Get() const
		{
			return m_Cap;
		}
	private:
		SkPaint::Cap m_Cap;
	};

	class SStrokeJoin{
	public:
		SStrokeJoin(int iStyle){
			iStyle = iStyle & PS_JOIN_MASK;
			switch(iStyle)
			{
			case PS_JOIN_ROUND: m_Join = SkPaint::kRound_Join;break;
			case PS_JOIN_BEVEL: m_Join = SkPaint::kBevel_Join;break;
			case PS_JOIN_MITER:default: m_Join = SkPaint::kDefault_Join; break;

			}
		}
		SkPaint::Join Get() const
		{
			return m_Join;
		}
	private:
		SkPaint::Join m_Join;
	};
	//////////////////////////////////////////////////////////////////////////
	// SRenderFactory_Skia

	SRenderFactory_Skia::SRenderFactory_Skia()
	{
		SkGraphics::Init();
		SkGraphics::SetFontCacheCountLimit(500);//cache up to 500 font resource.
	}

	SRenderFactory_Skia::~SRenderFactory_Skia()
	{
		SkGraphics::Term();
	}

	BOOL SRenderFactory_Skia::CreateRenderTarget( IRenderTargetPtr &ppRenderTarget ,int nWid,int nHei)
	{
		ppRenderTarget = std::make_shared<SRenderTarget_Skia>(shared_from_this(), nWid, nHei);
		return TRUE;
	}

    BOOL SRenderFactory_Skia::CreateFont(IFontPtr& ppFont , const LOGFONT &lf )
    {
        ppFont = std::make_shared<SFont_Skia>(shared_from_this(), &lf);
        return TRUE;
    }

    BOOL SRenderFactory_Skia::CreateBitmap(IBitmapPtr &ppBitmap )
    {
        ppBitmap = std::make_shared<SBitmap_Skia>(shared_from_this());
        return TRUE;
    }

    BOOL SRenderFactory_Skia::CreateRegion(IRegionPtr &ppRgn )
    {
        ppRgn = std::make_shared < SRegion_Skia>(shared_from_this());
        return TRUE;
    }

	BOOL SRenderFactory_Skia::CreatePath(IPathPtr &ppPath)
	{
		ppPath = std::make_shared<SPath_Skia>(shared_from_this());
		return TRUE;
	}

	BOOL SRenderFactory_Skia::CreatePathEffect(REFGUID guidEffect,IPathEffectPtr &ppPathEffect)
	{
		ppPathEffect = NULL;
		if(guidEffect == __uuidof(ICornerPathEffect))
		{
			ppPathEffect = std::make_shared<SPathEffect_Corner>();
		}else if(guidEffect == __uuidof(IDashPathEffect))
		{
			ppPathEffect = std::make_shared<SPathEffect_Dash>();
		}else if(guidEffect == __uuidof(IDiscretePathEffect))
		{
			ppPathEffect = std::make_shared<SPathEffect_Discrete>();
		}
		return ppPathEffect != NULL;
	}

	BOOL SRenderFactory_Skia::CreatePathMeasure(IPathMeasurePtr &ppPathMeasure)
	{
		ppPathMeasure = std::make_shared<SPathMeasure_Skia>();
		return TRUE;
	}

	HRESULT SRenderFactory_Skia::CreateBlurMaskFilter(float radius, IMaskFilter::SkBlurStyle style,IMaskFilter::SkBlurFlags flag,IMaskFilterPtr &ppMaskFilter)
	{
		SkMaskFilter *pMaskFilter = SkBlurMaskFilter::Create(::SkBlurStyle(style),SkBlurMaskFilter::ConvertRadiusToSigma(radius),flag);
		if(!pMaskFilter)
			return E_OUTOFMEMORY;
		ppMaskFilter = std::make_shared < SMaskFilter_Skia>(pMaskFilter);
		return S_OK;
	}


	HRESULT SRenderFactory_Skia::CreateEmbossMaskFilter(float direction[3], float ambient, float specular, float blurRadius,IMaskFilterPtr &ppMaskFilter)
	{
		SkMaskFilter *pMaskFilter=SkBlurMaskFilter::CreateEmboss(direction,ambient,specular,SkBlurMaskFilter::ConvertRadiusToSigma(blurRadius));
		if(!pMaskFilter)
			return E_OUTOFMEMORY;
		ppMaskFilter = std::make_shared < SMaskFilter_Skia>(pMaskFilter);
		return S_OK;
	}
    //////////////////////////////////////////////////////////////////////////
	// SRenderTarget_Skia

	SRenderTarget_Skia::SRenderTarget_Skia( IRenderFactoryPtr pRenderFactory ,int nWid,int nHei)
		:m_SkCanvas(NULL)
        ,m_curColor(0xFF000000)//默认黑色
        ,m_hGetDC(0)
        ,m_uGetDCFlag(0)
		,m_bAntiAlias(true)
		,m_xferMode(kSrcOver_Mode)
	{
        m_ptOrg.fX=m_ptOrg.fY=0.0f;
        m_pRenderFactory = pRenderFactory;

        m_SkCanvas = new SkCanvas();
		m_paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
		m_paint.setAntiAlias(true);
		m_paint.setLCDRenderText(true);
		m_paint.setStyle(SkPaint::kStrokeAndFill_Style);

		IPenPtr pen;
		IRenderObjPtr oldPen;
        CreatePen(PS_SOLID,SColor(0,0,0).toCOLORREF(),1, pen);
		m_defPen = pen;
        SelectObject(pen, oldPen);

		IBrushPtr brush;
		IRenderObjPtr oldBrush;
        CreateSolidColorBrush(SColor(0,0,0).toCOLORREF(), brush);
		m_defBrush = brush;
        SelectObject(brush, oldBrush);

        LOGFONT lf={0};
        lf.lfHeight=20;
        _tcscpy(lf.lfFaceName,_T("宋体"));
		IFontPtr font;
		IRenderObjPtr oldFont;
        pRenderFactory->CreateFont(font,lf);
		m_defFont = font;
        SelectObject(font, oldFont);

		IBitmapPtr bitmap;
		IRenderObjPtr oldBitmap;
        pRenderFactory->CreateBitmap(bitmap);
		m_defBmp = bitmap;
		bitmap->Init(nWid,nHei);
        SelectObject(bitmap, oldBitmap);
	}
	
	SRenderTarget_Skia::~SRenderTarget_Skia()
	{
		if(m_SkCanvas) delete m_SkCanvas;
	}

	HRESULT SRenderTarget_Skia::CreateCompatibleRenderTarget( SIZE szTarget,IRenderTargetPtr &ppRenderTarget )
	{
		ppRenderTarget = std::make_shared<SRenderTarget_Skia>(m_pRenderFactory,szTarget.cx,szTarget.cy);
		return S_OK;
	}

	HRESULT SRenderTarget_Skia::CreatePen( int iStyle,COLORREF cr,int cWidth,IPenPtr &ppPen )
	{
		ppPen = std::make_shared < SPen_Skia>(m_pRenderFactory,iStyle,cr,cWidth);
		return S_OK;
	}

	HRESULT SRenderTarget_Skia::CreateSolidColorBrush( COLORREF cr,IBrushPtr &ppBrush )
	{
		ppBrush = SBrush_Skia::CreateSolidBrush(m_pRenderFactory,cr);
		return S_OK;
	}

	HRESULT SRenderTarget_Skia::CreateBitmapBrush( IBitmapPtr pBmp,IBrushPtr &ppBrush )
	{
		SBitmap_SkiaPtr pBmpSkia = std::dynamic_pointer_cast<SBitmap_Skia>(pBmp);
		ppBrush = SBrush_Skia::CreateBitmapBrush(m_pRenderFactory,pBmpSkia->GetSkBitmap());
		return S_OK;
	}

	HRESULT SRenderTarget_Skia::CreateRegion(IRegionPtr &ppRegion)
	{
		return m_pRenderFactory->CreateRegion(ppRegion)?S_OK:E_OUTOFMEMORY;
	}

	HRESULT SRenderTarget_Skia::Resize( SIZE sz )
	{
    	m_curBmp->Init(sz.cx,sz.cy);
        delete m_SkCanvas;
        m_SkCanvas = new SkCanvas(m_curBmp->GetSkBitmap());
		return S_OK;
	}

	HRESULT SRenderTarget_Skia::PushClipRect( LPCRECT pRect ,UINT mode/*=RGN_AND*/)
	{
        SkRect skrc=toSkRect(pRect);
        skrc.offset(m_ptOrg);
        
        m_SkCanvas->save();

        m_SkCanvas->clipRect(skrc,SRegion_Skia::RGNMODE2SkRgnOP(mode));
	    return S_OK;
	}

	HRESULT SRenderTarget_Skia::PushClipRegion( IRegionPtr pRegion ,UINT mode/*=RGN_AND*/)
	{
        SRegion_SkiaPtr rgn_skia= std::dynamic_pointer_cast<SRegion_Skia>(pRegion);
        SkRegion rgn=rgn_skia->GetRegion();
        rgn.translate((int)m_ptOrg.fX,(int)m_ptOrg.fY);

        m_SkCanvas->save();

        m_SkCanvas->clipRegion(rgn,SRegion_Skia::RGNMODE2SkRgnOP(mode));
        
		return S_OK;
	}

    HRESULT SRenderTarget_Skia::PopClip()
    {
        m_SkCanvas->restore();
        return S_OK;
    }

    HRESULT SRenderTarget_Skia::ExcludeClipRect( LPCRECT pRc )
    {
        SkRect skrc=toSkRect(pRc);
        skrc.offset(m_ptOrg);
        m_SkCanvas->clipRect(skrc,SkRegion::kDifference_Op);
        return S_OK;
    }

    HRESULT SRenderTarget_Skia::IntersectClipRect( LPCRECT pRc )
    {
        SkRect skrc=toSkRect(pRc);
        skrc.offset(m_ptOrg);
        m_SkCanvas->clipRect(skrc,SkRegion::kIntersect_Op);
        return S_OK;
    }

    HRESULT SRenderTarget_Skia::SaveClip( int *pnState )
    {
        int nState=m_SkCanvas->save();
        if(pnState) *pnState=nState;
        return S_OK;
    }

    HRESULT SRenderTarget_Skia::RestoreClip( int nState/*=-1*/ )
    {
        m_SkCanvas->restoreToCount(nState);
        return S_OK;
    }

    HRESULT SRenderTarget_Skia::GetClipRegion( IRegionPtr &ppRegion )
    {
        SRegion_SkiaPtr pRgn = std::make_shared<SRegion_Skia>(m_pRenderFactory);
        SkRegion rgn = m_SkCanvas->getTotalClip();
        //需要将rect的viewOrg还原
        rgn.translate((int)-m_ptOrg.fX,(int)-m_ptOrg.fY);
        pRgn->SetRegion(rgn);
        ppRegion = pRgn;
        return S_OK;
    }

    HRESULT SRenderTarget_Skia::GetClipBox(LPRECT prc)
    {
        SkRect skrc;
        m_SkCanvas->getClipBounds(&skrc);
        //需要将rect的viewOrg还原
        skrc.offset(-m_ptOrg);

        prc->left=(LONG)skrc.fLeft;
        prc->top=(LONG)skrc.fTop;
        prc->right=(LONG)skrc.fRight;
        prc->bottom=(LONG)skrc.fBottom;
        //需要4周缩小一个单位才是和GDI相同的剪裁区
        ::InflateRect(prc,-1,-1);
        return S_OK;
    }
    
	HRESULT SRenderTarget_Skia::BitBlt( LPCRECT pRcDest,IRenderTargetPtr pRTSour,int xSrc,int ySrc,DWORD dwRop/*=SRCCOPY*/)
	{
        SkPaint paint=m_paint;
        paint.setStyle(SkPaint::kFill_Style);
		SetPaintXferMode(paint,dwRop);

        SRenderTarget_SkiaPtr pRtSourSkia= std::dynamic_pointer_cast<SRenderTarget_Skia>(pRTSour);
        const SkBitmap  &  bmpSrc=pRtSourSkia->m_curBmp->GetSkBitmap();
        POINT ptSourViewport;
        pRtSourSkia->GetViewportOrg(&ptSourViewport);
        xSrc += ptSourViewport.x;
        ySrc += ptSourViewport.y;
        
        
        SkIRect isrc={xSrc,ySrc,xSrc + pRcDest->right-pRcDest->left,ySrc+pRcDest->bottom-pRcDest->top};
        SkRect skrc=toSkRect(pRcDest);
        skrc.offset(m_ptOrg);
        m_SkCanvas->drawBitmapRect(bmpSrc,&isrc,skrc,&paint);
		return S_OK;
	}

	HRESULT SRenderTarget_Skia::DrawText( LPCTSTR pszText,int cchLen,LPRECT pRc,UINT uFormat)
	{
		if(cchLen<0) cchLen= _tcslen(pszText);
		if(cchLen==0)
        {
            if(uFormat & DT_CALCRECT)
            {
                pRc->right=pRc->left;
                pRc->bottom=pRc->top;
            }
            return S_OK;
        }
		
        SkPaint     txtPaint = m_paint;
		SFont_SkiaPtr pFont = m_curFont;
        txtPaint.setTypeface(pFont->GetFont());
		txtPaint.setTextSize(SkIntToScalar(abs(pFont->TextSize())));
		txtPaint.setUnderlineText(pFont->IsUnderline());
		txtPaint.setStrikeThruText(pFont->IsStrikeOut());
		txtPaint.setStyle(SkPaint::kStrokeAndFill_Style);
		if(pFont->GetBlurFilter())
		{
			txtPaint.setMaskFilter(pFont->GetBlurFilter());
		}

        if(uFormat & DT_CENTER)
            txtPaint.setTextAlign(SkPaint::kCenter_Align);
        else if(uFormat & DT_RIGHT)
            txtPaint.setTextAlign(SkPaint::kRight_Align);
		else
			txtPaint.setTextAlign(SkPaint::kLeft_Align);
        SkRect skrc=toSkRect(pRc);
        skrc.offset(m_ptOrg);
        skrc=DrawText_Skia(m_SkCanvas, pszText, cchLen,skrc,txtPaint,uFormat);
        if(uFormat & DT_CALCRECT)
        {
            pRc->left=(int)skrc.fLeft;
            pRc->top=(int)skrc.fTop;
            pRc->right=(int)skrc.fRight;
            pRc->bottom=(int)skrc.fBottom;
        }
		return S_OK;
	}

	HRESULT SRenderTarget_Skia::MeasureText( LPCTSTR pszText,int cchLen, SIZE *psz )
	{
        SkPaint     txtPaint = m_paint;
        txtPaint.setTypeface(m_curFont->GetFont());
		txtPaint.setTextSize(SkIntToScalar(abs(m_curFont->TextSize())));
        psz->cx = (int)txtPaint.measureText(pszText, cchLen *sizeof(wchar_t));
        
        SkPaint::FontMetrics metrics;
        txtPaint.getFontMetrics(&metrics);
        psz->cy = (int)(metrics.fBottom-metrics.fTop);
		return S_OK;
	}

	HRESULT SRenderTarget_Skia::DrawRectangle(LPCRECT pRect)
	{
		SkPaint paint=m_paint;
		paint.setColor(SColor(m_curPen->GetColor()).toARGB());
		SLineDashEffect skDash(m_curPen->GetStyle());
 		paint.setPathEffect(skDash.Get());
		SStrokeCap strokeCap(m_curPen->GetStyle());
		paint.setStrokeCap(strokeCap.Get());
		SStrokeJoin strokeJoin(m_curPen->GetStyle());
		paint.setStrokeJoin(strokeJoin.Get());
		if(m_bAntiAlias)
		{
			paint.setAntiAlias(true);
			paint.setStrokeWidth((SkScalar)m_curPen->GetWidth()-0.5f);
		}else
		{
			paint.setAntiAlias(false);
			paint.setStrokeWidth((SkScalar)m_curPen->GetWidth());
		}
		paint.setStyle(SkPaint::kStroke_Style);

        SkRect skrc=toSkRect(pRect);
        skrc.offset(m_ptOrg);
        InflateSkRect(&skrc,-0.5f,-0.5f);
		m_SkCanvas->drawRect(skrc,paint);
		return S_OK;
	}

	HRESULT SRenderTarget_Skia::FillRectangle(LPCRECT pRect)
	{
		SkPaint paint=m_paint;
		if(m_curBrush->IsBitmap())
		{
			paint.setFilterBitmap(true);
			paint.setShader(SkShader::CreateBitmapShader(m_curBrush->GetBitmap(),SkShader::kRepeat_TileMode,SkShader::kRepeat_TileMode))->unref();
		}else
		{
			paint.setFilterBitmap(false);
			paint.setColor(SColor(m_curBrush->GetColor()).toARGB());
		}
		paint.setStyle(SkPaint::kFill_Style);

        SkRect skrc=toSkRect(pRect);
        skrc.offset(m_ptOrg);
        InflateSkRect(&skrc,-0.5f,-0.5f);
		m_SkCanvas->drawRect(skrc,paint);
		return S_OK;
	}

    HRESULT SRenderTarget_Skia::DrawRoundRect( LPCRECT pRect,POINT pt )
    {
        SkPaint paint=m_paint;
		SetPaintXferMode(paint,m_xferMode);
        paint.setColor(SColor(m_curPen->GetColor()).toARGB());
        SLineDashEffect skDash(m_curPen->GetStyle());
        paint.setPathEffect(skDash.Get());
        paint.setStyle(SkPaint::kStroke_Style);
		if(m_bAntiAlias)
		{
			paint.setStrokeWidth((SkScalar)m_curPen->GetWidth()-0.5f);
		}else
		{
			paint.setStrokeWidth((SkScalar)m_curPen->GetWidth());
		}

        SkRect skrc=toSkRect(pRect);
        InflateSkRect(&skrc,-0.5f,-0.5f);//要缩小0.5显示效果才和GDI一致。
        skrc.offset(m_ptOrg);
        m_SkCanvas->drawRoundRect(skrc,(SkScalar)pt.x,(SkScalar)pt.y,paint);
        return S_OK;
    }

    HRESULT SRenderTarget_Skia::FillRoundRect( LPCRECT pRect,POINT pt )
    {
        SkPaint paint=m_paint;

        if(m_curBrush->IsBitmap())
        {
            paint.setFilterBitmap(true);
            paint.setShader(SkShader::CreateBitmapShader(m_curBrush->GetBitmap(),SkShader::kRepeat_TileMode,SkShader::kRepeat_TileMode))->unref();
        }else
        {
            paint.setFilterBitmap(false);
            paint.setColor(m_curBrush->GetColor());
        }
        paint.setStyle(SkPaint::kFill_Style);

        SkRect skrc=toSkRect(pRect);
        InflateSkRect(&skrc,-0.5f,-0.5f);//要缩小0.5显示效果才和GDI一致。
        skrc.offset(m_ptOrg);

        m_SkCanvas->drawRoundRect(skrc,(SkScalar)pt.x,(SkScalar)pt.y,paint);
        return S_OK;
    }
    
    HRESULT SRenderTarget_Skia::FillSolidRoundRect(LPCRECT pRect,POINT pt,COLORREF cr)
    {
        SkPaint paint=m_paint;

        paint.setFilterBitmap(false);
        paint.setColor(SColor(cr).toARGB());
        paint.setStyle(SkPaint::kFill_Style);

        SkRect skrc=toSkRect(pRect);
        InflateSkRect(&skrc,-0.5f,-0.5f);//要缩小0.5显示效果才和GDI一致。
        skrc.offset(m_ptOrg);

        m_SkCanvas->drawRoundRect(skrc,(SkScalar)pt.x,(SkScalar)pt.y,paint);
        return S_OK;
    }


    HRESULT SRenderTarget_Skia::DrawLines(LPPOINT pPt,size_t nCount)
    {
        SkPoint *pts=new SkPoint[nCount];
        for(size_t i=0; i<nCount; i++ )
        {
            pts[i].fX = (SkScalar)pPt[i].x;
            pts[i].fY = (SkScalar)pPt[i].y;
        }
        SkPoint::Offset(pts,nCount,m_ptOrg);

        SkPaint paint=m_paint;
		if(m_bAntiAlias)
		{
			paint.setStrokeWidth((SkScalar)m_curPen->GetWidth()-0.5f);
		}else
		{
			paint.setStrokeWidth((SkScalar)m_curPen->GetWidth());
		}

        paint.setColor(SColor(m_curPen->GetColor()).toARGB());
        SLineDashEffect skDash(m_curPen->GetStyle());
        paint.setPathEffect(skDash.Get());
		SStrokeCap strokeCap(m_curPen->GetStyle());
		paint.setStrokeCap(strokeCap.Get());
		SStrokeJoin strokeJoin(m_curPen->GetStyle());
		paint.setStrokeJoin(strokeJoin.Get());
        paint.setStyle(SkPaint::kStroke_Style);
        m_SkCanvas->drawPoints(SkCanvas::kPolygon_PointMode,nCount,pts,paint);
        delete []pts;

        return S_OK;
    }

	HRESULT SRenderTarget_Skia::TextOut( int x, int y, LPCTSTR lpszString, int nCount)
	{
		if(nCount<0) nCount= _tcslen(lpszString);
        SkPaint     txtPaint =m_paint;
		txtPaint.setStyle(SkPaint::kStrokeAndFill_Style);
		txtPaint.setTypeface(m_curFont->GetFont());
		txtPaint.setTextSize(SkIntToScalar(abs(m_curFont->TextSize())));
		txtPaint.setUnderlineText(m_curFont->IsUnderline());
		txtPaint.setStrikeThruText(m_curFont->IsStrikeOut());

        SkPaint::FontMetrics metrics;
        txtPaint.getFontMetrics(&metrics);
        SkScalar fx = m_ptOrg.fX + x;
        SkScalar fy = m_ptOrg.fY + y;
        fy -= metrics.fTop;

		m_SkCanvas->drawText((LPCWSTR)lpszString, nCount*2,fx,fy,txtPaint);
		return S_OK;
	}

    HRESULT SRenderTarget_Skia::DrawIconEx( int xLeft, int yTop, HICON hIcon, int cxWidth,int cyWidth,UINT diFlags )
    {
        HDC hdc=GetDC(0);
		
        ICONINFO ii={0};
        ::GetIconInfo(hIcon,&ii);
        assert(ii.hbmColor);
        BITMAP bm;
        ::GetObject(ii.hbmColor,sizeof(bm),&bm);

        ALPHAINFO ai;
        RECT rc={xLeft,yTop,xLeft+cxWidth,yTop+cyWidth};
        if(bm.bmBitsPixel!=32)
        {
            CGdiAlpha::AlphaBackup(hdc,&rc,ai);
        }
        BOOL bRet=::DrawIconEx(hdc,xLeft,yTop,hIcon,cxWidth,cyWidth,0,NULL,diFlags);

        if(bm.bmBitsPixel!=32)
        {
            CGdiAlpha::AlphaRestore(ai);
        }
        if(ii.hbmColor) DeleteObject(ii.hbmColor);
        if(ii.hbmMask) DeleteObject(ii.hbmMask);

        ReleaseDC(hdc);
        return bRet?S_OK:S_FALSE;
    }

    HRESULT SRenderTarget_Skia::DrawBitmap(LPCRECT pRcDest,IBitmapPtr pBitmap,int xSrc,int ySrc,BYTE byAlpha/*=0xFF*/ )
    {
        SBitmap_SkiaPtr pBmp = std::dynamic_pointer_cast<SBitmap_Skia>(pBitmap);
        const SkBitmap & bmp=pBmp->GetSkBitmap();

        SIZE szBmp = pBmp->Size();
        int nWid= (std::min)(pRcDest->right-pRcDest->left,szBmp.cx);
        int nHei= (std::min)(pRcDest->bottom-pRcDest->top,szBmp.cy);

        RECT rcSrc={xSrc,ySrc,xSrc+nWid,ySrc+nHei};
        RECT rcDst={pRcDest->left,pRcDest->top,pRcDest->left+nWid,pRcDest->top+nHei};
        
        SkRect skrcSrc= toSkRect(&rcSrc);
        SkRect skrcDst = toSkRect(&rcDst);
        
        skrcDst.offset(m_ptOrg);

        SkPaint paint=m_paint;
        
        if(byAlpha != 0xFF) paint.setAlpha(byAlpha);
        m_SkCanvas->drawBitmapRectToRect(bmp,&skrcSrc,skrcDst,&paint);
        return S_OK;
    }
    
    HRESULT SRenderTarget_Skia::AlphaBlend( LPCRECT pRcDest,IRenderTargetPtr pRTSrc,LPCRECT pRcSrc,BYTE byAlpha )
    {
        IBitmapPtr pBmp= std::dynamic_pointer_cast<IBitmap>( pRTSrc->GetCurrentObject(OT_BITMAP));
        if(!pBmp) return S_FALSE;
        RECT rcSrc = *pRcSrc;
        POINT ptSrcOrg;
        pRTSrc->GetViewportOrg(&ptSrcOrg);
		SRenderTarget_SkiaPtr pRTSrc_Skia= std::dynamic_pointer_cast<SRenderTarget_Skia>(pRTSrc);
		SkMatrix mtx = pRTSrc_Skia->m_SkCanvas->getTotalMatrix();
		if(!mtx.isIdentity())
		{
			SkRect rc=toSkRect(&rcSrc);
			mtx.mapRect(&rc);
			SkRect2RECT(rc,&rcSrc);
		}
        OffsetRect(&rcSrc,ptSrcOrg.x,ptSrcOrg.y);
        return DrawBitmapEx(pRcDest,pBmp,&rcSrc,EM_STRETCH,byAlpha);
    }

    HRESULT SRenderTarget_Skia::DrawBitmapEx( LPCRECT pRcDest,IBitmapPtr pBitmap,LPCRECT pRcSrc,UINT expendMode, BYTE byAlpha/*=0xFF*/ )
    {
        UINT expendModeLow = LOWORD(expendMode);

		const SkMatrix & m = m_SkCanvas->getTotalMatrix();

        if(m.isIdentity() && ( expendModeLow == EM_NULL || (RectWid(pRcDest)==RectWid(pRcSrc) && RectHei(pRcDest)==RectHei(pRcSrc))))
            return DrawBitmap(pRcDest,pBitmap,pRcSrc->left,pRcSrc->top,byAlpha);
            
        SBitmap_SkiaPtr pBmp = std::dynamic_pointer_cast<SBitmap_Skia>(pBitmap);
        const SkBitmap & bmp=pBmp->GetSkBitmap();

        RECT rcSour={0,0,bmp.width(),bmp.height()};
        if(!pRcSrc) pRcSrc = &rcSour;
        SkRect rcSrc = toSkRect(pRcSrc);
        SkRect rcDest= toSkRect(pRcDest);
        rcDest.offset(m_ptOrg);

        SkPaint paint=m_paint;
        if(byAlpha != 0xFF) paint.setAlpha(byAlpha);
        
        SkPaint::FilterLevel fl = (SkPaint::FilterLevel)HIWORD(expendMode);//SkPaint::kNone_FilterLevel;
        paint.setFilterLevel(fl);
                
        if(expendModeLow == EM_STRETCH)
        {
            m_SkCanvas->drawBitmapRectToRect(bmp,&rcSrc,rcDest,&paint);
        }else
        {
            PushClipRect(pRcDest,RGN_AND);
            
            SkIRect rcSrc = toSkIRect(pRcSrc);
            SkRect rcSubDest={0.0f,0.0f,(float)rcSrc.width(),(float)rcSrc.height()};
            for(float y=rcDest.fTop;y<rcDest.fBottom;y+=rcSrc.height())
            {
                rcSubDest.offsetTo(rcDest.fLeft,y);               
                for(float x=rcDest.fLeft;x<rcDest.fRight;x += rcSrc.width())
                {
                    m_SkCanvas->drawBitmapRect(bmp,&rcSrc,rcSubDest,&paint);
                    rcSubDest.offset((float)rcSrc.width(),0.0f);
                }
            }
            
            PopClip();
        }
        return S_OK;

    }


    HRESULT SRenderTarget_Skia::DrawBitmap9Patch( LPCRECT pRcDest,IBitmapPtr pBitmap,LPCRECT pRcSrc,LPCRECT pRcSourMargin,UINT expendMode,BYTE byAlpha/*=0xFF*/ )
    {
        int xDest[4] = {pRcDest->left,pRcDest->left+pRcSourMargin->left,pRcDest->right-pRcSourMargin->right,pRcDest->right};
        int xSrc[4] = {pRcSrc->left,pRcSrc->left+pRcSourMargin->left,pRcSrc->right-pRcSourMargin->right,pRcSrc->right};
        int yDest[4] = {pRcDest->top,pRcDest->top+pRcSourMargin->top,pRcDest->bottom-pRcSourMargin->bottom,pRcDest->bottom};
        int ySrc[4] = {pRcSrc->top,pRcSrc->top+pRcSourMargin->top,pRcSrc->bottom-pRcSourMargin->bottom,pRcSrc->bottom};
        
        //首先保证九宫分割正常
        if(!(xSrc[0] <= xSrc[1] && xSrc[1] <= xSrc[2] && xSrc[2] <= xSrc[3])) return S_FALSE;
        if(!(ySrc[0] <= ySrc[1] && ySrc[1] <= ySrc[2] && ySrc[2] <= ySrc[3])) return S_FALSE;
        
        //调整目标位置
        int nDestWid=pRcDest->right-pRcDest->left;
        int nDestHei=pRcDest->bottom-pRcDest->top;
        
        if((pRcSourMargin->left + pRcSourMargin->right) > nDestWid)
        {//边缘宽度大于目标宽度的处理
            if(pRcSourMargin->left >= nDestWid)
            {//只绘制左边部分
                xSrc[1] = xSrc[2] = xSrc[3] = xSrc[0]+nDestWid;
                xDest[1] = xDest[2] = xDest[3] = xDest[0]+nDestWid;
            }else if(pRcSourMargin->right >= nDestWid)
            {//只绘制右边部分
                xSrc[0] = xSrc[1] = xSrc[2] = xSrc[3]-nDestWid;
                xDest[0] = xDest[1] = xDest[2] = xDest[3]-nDestWid;
            }else
            {//先绘制左边部分，剩余的用右边填充
                int nRemain=xDest[3]-xDest[1];
                xSrc[2] = xSrc[3]-nRemain;
                xDest[2] = xDest[3]-nRemain;
            }
        }
        
        if(pRcSourMargin->top + pRcSourMargin->bottom > nDestHei)
        {
            if(pRcSourMargin->top >= nDestHei)
            {//只绘制上边部分
                ySrc[1] = ySrc[2] = ySrc[3] = ySrc[0]+nDestHei;
                yDest[1] = yDest[2] = yDest[3] = yDest[0]+nDestHei;
            }else if(pRcSourMargin->bottom >= nDestHei)
            {//只绘制下边部分
                ySrc[0] = ySrc[1] = ySrc[2] = ySrc[3]-nDestHei;
                yDest[0] = yDest[1] = yDest[2] = yDest[3]-nDestHei;
            }else
            {//先绘制左边部分，剩余的用右边填充
                int nRemain=yDest[3]-yDest[1];
                ySrc[2] = ySrc[3]-nRemain;
                yDest[2] = yDest[3]-nRemain;
            }
        }
        
        //定义绘制模式
        UINT mode[3][3]={
        {EM_NULL,expendMode,EM_NULL},
        {expendMode,expendMode,expendMode},
        {EM_NULL,expendMode,EM_NULL}
        };
        
        for(int y=0;y<3;y++)
        {
            if(ySrc[y] == ySrc[y+1]) continue;
            for(int x=0;x<3;x++)
            {
                if(xSrc[x] == xSrc[x+1]) continue;
                RECT rcSrc = {xSrc[x],ySrc[y],xSrc[x+1],ySrc[y+1]};
                RECT rcDest ={xDest[x],yDest[y],xDest[x+1],yDest[y+1]};
                DrawBitmapEx(&rcDest,pBitmap,&rcSrc,mode[y][x],byAlpha);
            }
        }
        
        return S_OK;
    }

	IRenderObjPtr SRenderTarget_Skia::GetCurrentObject( OBJTYPE uType )
	{
		IRenderObjPtr pRet=NULL;
		switch(uType)
		{
		case OT_BITMAP: 
			pRet=m_curBmp;
			break;
		case OT_PEN:
			pRet=m_curPen;
			break;
		case OT_BRUSH:
			pRet=m_curBrush;
			break;
        case OT_FONT:
            pRet=m_curFont;
            break;
		}
		return pRet;
	}


    HRESULT SRenderTarget_Skia::SelectDefaultObject(OBJTYPE objType,IRenderObjPtr &ppOldObj /*= NULL*/)
    {
        IRenderObjPtr pDefObj = NULL;
        switch(objType)
        {
        case OT_BITMAP: pDefObj = m_defBmp;break;
        case OT_PEN: pDefObj = m_defPen;break;
        case OT_BRUSH: pDefObj = m_defBrush;break;
        case OT_FONT: pDefObj = m_defFont;break;
        default:return E_INVALIDARG;
        }
        if(pDefObj == GetCurrentObject(objType)) 
            return S_FALSE;
        return SelectObject(pDefObj,ppOldObj);
    }

    HRESULT SRenderTarget_Skia::SelectObject( IRenderObjPtr pObj,IRenderObjPtr &ppOldObj /*= NULL*/ )
    {
        IRenderObjPtr pRet;
        switch(pObj->ObjectType())
        {
        case OT_BITMAP: 
            pRet=m_curBmp;
            m_curBmp= std::dynamic_pointer_cast<SBitmap_Skia>(pObj);
            //重新生成clip
            assert(m_SkCanvas);
            delete m_SkCanvas;
            m_SkCanvas = new SkCanvas(m_curBmp->GetSkBitmap());
            break;
        case OT_PEN:
            pRet=m_curPen;
            m_curPen= std::dynamic_pointer_cast<SPen_Skia>(pObj);
            break;
        case OT_BRUSH:
            pRet=m_curBrush;
            m_curBrush= std::dynamic_pointer_cast<SBrush_Skia>(pObj);
            break;
        case OT_FONT:
            pRet=m_curFont;
            m_curFont= std::dynamic_pointer_cast<SFont_Skia>(pObj);
            break;
        }
		
		ppOldObj = pRet;
        
        return S_OK;
    }

    HRESULT SRenderTarget_Skia::OffsetViewportOrg( int xOff, int yOff, LPPOINT lpPoint )
    {
		SkMatrix mtx=m_SkCanvas->getTotalMatrix();
		SkPoint ptOff={(SkScalar)xOff,(SkScalar)yOff};
        if(lpPoint)
        {
            lpPoint->x = (LONG)m_ptOrg.fX;
            lpPoint->y = (LONG)m_ptOrg.fY;
        }
        m_ptOrg.offset(ptOff.fX,ptOff.fY);
        return S_OK;
    }

    HRESULT SRenderTarget_Skia::GetViewportOrg( LPPOINT lpPoint )
    {
        if(lpPoint)
        {
            lpPoint->x = (LONG)m_ptOrg.fX;
            lpPoint->y = (LONG)m_ptOrg.fY;
        }
        return S_OK;
    }
    
    HRESULT SRenderTarget_Skia::SetViewportOrg( POINT pt )
    {
        m_ptOrg.fX = SkIntToScalar(pt.x);
        m_ptOrg.fY = SkIntToScalar(pt.y);
        return S_OK;
    }


    HDC SRenderTarget_Skia::GetDC( UINT uFlag )
    {
        if(m_hGetDC) return m_hGetDC;
        
        HBITMAP bmp=m_curBmp->GetGdiBitmap();//bmp可能为NULL
        HDC hdc_desk = ::GetDC(NULL);
        m_hGetDC = CreateCompatibleDC(hdc_desk);
        ::ReleaseDC(NULL,hdc_desk);
        
        ::SelectObject(m_hGetDC,bmp);
        
        if(m_SkCanvas->isClipEmpty())
        {
            ::IntersectClipRect(m_hGetDC,0,0,0,0);
        }else if(m_SkCanvas->isClipRect())
        {
            SkRect rcClip;
            m_SkCanvas->getClipBounds(&rcClip);
            RECT rc = {(int)rcClip.left(),(int)rcClip.top(),(int)rcClip.right(),(int)rcClip.bottom()};
            ::InflateRect(&rc,-1,-1);//注意需要向内缩小一个象素
            ::IntersectClipRect(m_hGetDC,rc.left,rc.top,rc.right,rc.bottom);
        }else
        {
            SkRegion rgn = m_SkCanvas->getTotalClip();
            SkRegion::Iterator it(rgn);
            int nCount=0;
            for(;!it.done();it.next())
            {
                nCount++;
            }
            it.rewind();

            int nSize=sizeof(RGNDATAHEADER)+nCount*sizeof(RECT);
            RGNDATA *rgnData=(RGNDATA*)malloc(nSize);
            memset(rgnData,0,nSize);
            rgnData->rdh.dwSize= sizeof(RGNDATAHEADER);
            rgnData->rdh.iType = RDH_RECTANGLES;
            rgnData->rdh.nCount=nCount;
            rgnData->rdh.rcBound.right=m_curBmp->Width();
            rgnData->rdh.rcBound.bottom=m_curBmp->Height();

            nCount=0;
            LPRECT pRc=(LPRECT)rgnData->Buffer;
            for(;!it.done();it.next())
            {
                SkIRect skrc=it.rect();
                RECT rc = {skrc.fLeft,skrc.fTop,skrc.fRight,skrc.fBottom};
                pRc[nCount++]= rc;
            }

            HRGN hRgn=ExtCreateRegion(NULL,nSize,rgnData);
            free(rgnData);
            ::SelectClipRgn(m_hGetDC,hRgn);
            DeleteObject(hRgn);
        }

		::SetGraphicsMode(m_hGetDC,GM_ADVANCED);
		::SetViewportOrgEx(m_hGetDC,(int)m_ptOrg.x(),(int)m_ptOrg.y(),NULL);

		SkMatrix mtx=m_SkCanvas->getTotalMatrix();
		XFORM xForm = { mtx.get(IxForm::kMScaleX),mtx.get(IxForm::kMSkewY),
			mtx.get(IxForm::kMSkewX),mtx.get(IxForm::kMScaleY),
			mtx.get(IxForm::kMTransX),mtx.get(IxForm::kMTransY) };
		::SetWorldTransform(m_hGetDC,&xForm);

        m_uGetDCFlag = uFlag;
        return m_hGetDC;
    }

    void SRenderTarget_Skia::ReleaseDC( HDC hdc )
    {
        if(hdc == m_hGetDC)
        {
            DeleteDC(hdc);
            m_hGetDC = 0;
            m_uGetDCFlag =0;
        }
    }
    
    HRESULT SRenderTarget_Skia::GradientFillEx( LPCRECT pRect,const POINT* pts,COLORREF *colors,float *pos,int nCount,BYTE byAlpha/*=0xFF*/ )
    {
        SkRect skrc = toSkRect(pRect);
        skrc.offset(m_ptOrg);
        SkPoint *skPts = new SkPoint[nCount];
        SkColor *skColors= new SkColor[nCount];
        for(int i=0;i<nCount;i++)
        {
            skPts[i].iset(pts[i].x,pts[i].y);
            skPts[i].offset(m_ptOrg.x(),m_ptOrg.y());
            skColors[i] = SColor(colors[i],byAlpha).toARGB();
        }
        
        SkShader *pShader = SkGradientShader::CreateLinear(skPts, skColors, pos,nCount,SkShader::kMirror_TileMode);
        SkPaint paint=m_paint;
        paint.setShader(pShader)->unref();

        m_SkCanvas->drawRect(skrc,paint);

        delete []skColors;
        delete []skPts;
        return S_OK;
    }

	static bool fequal(float a,float b)
	{
		return fabs(a-b)< 0.0000001f;
	}

	HRESULT SRenderTarget_Skia::GradientFill2(LPCRECT pRect,GradientType type,COLORREF crStart,COLORREF crCenter,COLORREF crEnd,float fLinearAngle,float fCenterX,float fCenterY,int nRadius,BYTE byAlpha/*=0xff*/)
	{
		SkRect skrc = toSkRect(pRect);
		skrc.offset(m_ptOrg);

		SkColor *skColors= new SkColor[3];

		skColors[0]=SColor(crStart,byAlpha).toARGB();
		skColors[1]=SColor(crCenter,byAlpha).toARGB();
		skColors[2]=SColor(crEnd,byAlpha).toARGB();

		SkShader *pShader = NULL;
		SkScalar wid = skrc.width();
		SkScalar hei = skrc.height();
		SkScalar halfWid = wid/2;
		SkScalar halfHei = hei/2;
		if(type == linear)
		{

			SkPoint *skPts = new SkPoint[3];
			skPts[1].set(halfWid,halfHei);

			if(fequal(fLinearAngle,90.0f) || fequal(fLinearAngle,270.0f))
			{//90度
				skPts[0].set(halfWid,0.0f);
				skPts[2].set(halfWid,hei);
			}else if(fequal(fLinearAngle,0.0f) || fequal(fLinearAngle,180.0f))
			{//水平方向
				skPts[0].set(0.f ,halfHei);
				skPts[2].set(wid,halfHei);
			}else
			{//其它角度

				float angleInRadians = PI*fLinearAngle/180;
				double tanAngle = tan(angleInRadians);

				SkPoint pt1a,pt2a;//与左右两条边相交的位置
				SkPoint pt1b,pt2b;//与上下两条边相关的位置

				pt1a.fX=-halfWid,pt2a.fX=halfWid;
				pt1b.fY=-halfHei,pt2b.fY=halfHei;

				pt1a.fY= (SkScalar)(-halfWid*tanAngle);
				pt2a.fY = -pt1a.fY;

				pt1b.fX = (SkScalar)(-halfHei/tanAngle);
				pt2b.fX = -pt1b.fX;

				if(pt2a.fY > halfHei)
				{//using pt1a,pt2a
					skPts[0] = pt1a;
					skPts[2] = pt2a;
				}else
				{//using pt1b,pt2b
					skPts[0]=pt1b;
					skPts[2]=pt2b;
				}
			}
			pShader = SkGradientShader::CreateLinear(skPts, skColors, NULL,3,SkShader::kRepeat_TileMode);
			delete []skPts;
		}else if(type == radial)
		{
			SkPoint skCenter;
			skCenter.set(halfWid,halfHei);
			pShader = SkGradientShader::CreateRadial(skCenter,SkScalar(nRadius),skColors,NULL,3,SkShader::kRepeat_TileMode);
		}else if(type==sweep)
		{
			SkPoint skCenter;
			skCenter.set(halfWid,halfHei);
			pShader = SkGradientShader::CreateSweep(SkScalar(+fCenterX*wid),SkScalar(fCenterY*hei),skColors,NULL,3);
		}

		delete []skColors;

		if(!pShader)
		{
			return E_INVALIDARG;
		}

		SkPaint paint=m_paint;
		paint.setShader(pShader)->unref();

		SkPoint skOffset = {skrc.left(),skrc.top()};

 		m_SkCanvas->translate(skOffset.x(),skOffset.y());
 		skrc.offset(-skOffset.x(),-skOffset.y());
		m_SkCanvas->drawRect(skrc,paint);
		m_SkCanvas->translate(-skOffset.x(),-skOffset.y());
		return S_OK;
	}

    
    HRESULT SRenderTarget_Skia::GradientFill( LPCRECT pRect,BOOL bVert,COLORREF crBegin,COLORREF crEnd,BYTE byAlpha/*=0xFF*/ )
    {
        SkRect skrc = toSkRect(pRect);
        skrc.offset(m_ptOrg);

        SkPoint pts[2];
        pts[0].set(skrc.left(),skrc.top());

        if (bVert)
        {
            pts[1].set(skrc.left(),skrc.bottom());
        }
        else
        {
            pts[1].set(skrc.right(),skrc.top());
        }

        SColor cr1(crBegin,byAlpha);
        SColor cr2(crEnd,byAlpha);

        const SkColor colors[2] = {cr1.toARGB(),cr2.toARGB()};
        SkShader *pShader = SkGradientShader::CreateLinear(pts, colors, NULL,2,SkShader::kMirror_TileMode);
        SkPaint paint=m_paint;
        paint.setShader(pShader);
        pShader->unref();

        m_SkCanvas->drawRect(skrc,paint);
        return S_OK;

    }

    HRESULT SRenderTarget_Skia::FillSolidRect( LPCRECT pRect,COLORREF cr )
    {
        SkPaint paint=m_paint;
        paint.setStyle(SkPaint::kFill_Style);
        paint.setColor(SColor(cr).toARGB());
      
        SkRect skrc=toSkRect(pRect);
        skrc.offset(m_ptOrg);
        m_SkCanvas->drawRect(skrc,paint);
        return S_OK;    
    }

    HRESULT SRenderTarget_Skia::ClearRect( LPCRECT pRect,COLORREF cr )
    {
        SkPaint paint=m_paint;
        paint.setStyle(SkPaint::kFill_Style);
        paint.setColor(SColor(cr).toARGB());
        paint.setXfermodeMode(SkXfermode::kSrc_Mode);

        SkRect skrc=toSkRect(pRect);
        skrc.offset(m_ptOrg);
        m_SkCanvas->drawRect(skrc,paint);
        return S_OK;    
    }

    HRESULT SRenderTarget_Skia::InvertRect(LPCRECT pRect)
    {
        SkPaint paint=m_paint;
        paint.setStyle(SkPaint::kFill_Style);
        paint.setXfermode(new ProcXfermode(ProcXfermode::Rop2_Invert));
        SkRect skrc = toSkRect(pRect);
        skrc.offset(m_ptOrg);
        m_SkCanvas->drawRect(skrc,paint);
        return S_OK;  
    }

    HRESULT SRenderTarget_Skia::DrawEllipse( LPCRECT pRect )
    {
        SkPaint paint=m_paint;
        paint.setColor(SColor(m_curPen->GetColor()).toARGB());
        SLineDashEffect skDash(m_curPen->GetStyle());
        paint.setPathEffect(skDash.Get());
        paint.setStyle(SkPaint::kStroke_Style);
		if(m_bAntiAlias)
		{
			paint.setStrokeWidth((SkScalar)m_curPen->GetWidth()-0.5f);
		}else
		{
			paint.setStrokeWidth((SkScalar)m_curPen->GetWidth());
		}

        SkRect skrc = toSkRect(pRect);
        skrc.offset(m_ptOrg);
        m_SkCanvas->drawOval(skrc,paint);
        return S_OK;
    }

    HRESULT SRenderTarget_Skia::FillEllipse( LPCRECT pRect )
    {
        SkPaint paint=m_paint;
        if(m_curBrush->IsBitmap())
        {
            paint.setFilterBitmap(true);
            paint.setShader(SkShader::CreateBitmapShader(m_curBrush->GetBitmap(),SkShader::kRepeat_TileMode,SkShader::kRepeat_TileMode))->unref();
        }else
        {
            paint.setFilterBitmap(false);
            paint.setColor(SColor(m_curBrush->GetColor()).toARGB());
        }
        paint.setStyle(SkPaint::kFill_Style);

        SkRect skrc=toSkRect(pRect);
        skrc.offset(m_ptOrg);
        m_SkCanvas->drawOval(skrc,paint);
        return S_OK;
    }

    HRESULT SRenderTarget_Skia::FillSolidEllipse(LPCRECT pRect,COLORREF cr)
    {
        SkPaint paint=m_paint;
        paint.setFilterBitmap(false);
        paint.setColor(SColor(cr).toARGB());
        paint.setStyle(SkPaint::kFill_Style);

        SkRect skrc=toSkRect(pRect);
        skrc.offset(m_ptOrg);
        m_SkCanvas->drawOval(skrc,paint);
        return S_OK;
    }

    HRESULT SRenderTarget_Skia::DrawArc( LPCRECT pRect,float startAngle,float sweepAngle,bool useCenter )
    {
        SkPaint paint=m_paint;
        paint.setColor(SColor(m_curPen->GetColor()).toARGB());
        SLineDashEffect skDash(m_curPen->GetStyle());
        paint.setPathEffect(skDash.Get());
		SStrokeCap strokeCap(m_curPen->GetStyle());
		paint.setStrokeCap(strokeCap.Get());
        paint.setStyle(SkPaint::kStroke_Style);
		if(m_bAntiAlias)
		{
			paint.setStrokeWidth((SkScalar)m_curPen->GetWidth()-0.5f);
		}else
		{
			paint.setStrokeWidth((SkScalar)m_curPen->GetWidth());
		}

        SkRect skrc = toSkRect(pRect);
        skrc.offset(m_ptOrg);
        m_SkCanvas->drawArc(skrc,startAngle,sweepAngle,useCenter,paint);
        return S_OK;
    }

    HRESULT SRenderTarget_Skia::FillArc( LPCRECT pRect,float startAngle,float sweepAngle )
    {
        SkPaint paint=m_paint;
        if(m_curBrush->IsBitmap())
        {
            paint.setFilterBitmap(true);
            paint.setShader(SkShader::CreateBitmapShader(m_curBrush->GetBitmap(),SkShader::kRepeat_TileMode,SkShader::kRepeat_TileMode))->unref();
        }else
        {
            paint.setFilterBitmap(false);
            paint.setColor(SColor(m_curBrush->GetColor()).toARGB());
        }
        paint.setStyle(SkPaint::kFill_Style);
        SkRect skrc=toSkRect(pRect);
        skrc.offset(m_ptOrg);
        m_SkCanvas->drawArc(skrc,startAngle, sweepAngle,true,paint);
        return S_OK;
    }

    HRESULT SRenderTarget_Skia::SetTransform(const float matrix[9], float oldMatrix[9])
    {
        assert(matrix);
        if(oldMatrix) GetTransform(oldMatrix);
        SkMatrix m;
		m.setAll(matrix[IxForm::kMScaleX], matrix[IxForm::kMSkewX],matrix[IxForm::kMTransX],
			matrix[IxForm::kMSkewY],matrix[IxForm::kMScaleY],matrix[IxForm::kMTransY],
			matrix[IxForm::kMPersp0], matrix[IxForm::kMPersp1], matrix[IxForm::kMPersp2]
			);
		m.preTranslate(-m_ptOrg.fX, -m_ptOrg.fY);
		m.postTranslate(m_ptOrg.fX, m_ptOrg.fY);
		m_SkCanvas->setMatrix(m);
        return S_OK;
    }

    HRESULT SRenderTarget_Skia::GetTransform(float matrix[9]) const
    {
		assert(matrix);
        const SkMatrix & m = m_SkCanvas->getTotalMatrix();
		matrix[IxForm::kMScaleX] = m.getScaleX();
		matrix[IxForm::kMSkewX] = m.getSkewX();
		matrix[IxForm::kMTransX] = m.getTranslateX();
		matrix[IxForm::kMSkewY] = m.getSkewY();
		matrix[IxForm::kMScaleY] = m.getScaleY();
		matrix[IxForm::kMTransY] = m.getTranslateY();
		matrix[IxForm::kMPersp0] = m.getPerspX();
		matrix[IxForm::kMPersp1] = m.getPerspY();
		matrix[IxForm::kMPersp2] = m.get(SkMatrix::kMPersp2);

        return S_OK;
    }

	COLORREF SRenderTarget_Skia::GetPixel( int x, int y )
	{
		if(!m_curBmp) return CR_INVALID;
		const COLORREF *pBits = (const COLORREF*)m_curBmp->GetPixelBits();
		POINT pt;
		GetViewportOrg(&pt);
		x += pt.x;
		y += pt.y;
		if(x<0 || x >= (int)m_curBmp->Width() || y<0 || y>= (int)m_curBmp->Height())
			return CR_INVALID;
		
		return pBits[y*m_curBmp->Width()+x];
	}

	COLORREF SRenderTarget_Skia::SetPixel( int x, int y, COLORREF cr )
	{
		if(!m_curBmp) return CR_INVALID;
		COLORREF *pBits = (COLORREF*)m_curBmp->LockPixelBits();
		POINT pt;
		GetViewportOrg(&pt);
		x += pt.x;
		y += pt.y;

		if(x >= (int)m_curBmp->Width() || y>= (int)m_curBmp->Height())
			return CR_INVALID;

		COLORREF crRet = pBits[y*m_curBmp->Width()+x];

		pBits[y*m_curBmp->Width()+x] = cr;

		m_curBmp->UnlockPixelBits(pBits);

		return crRet;
	}

	HRESULT SRenderTarget_Skia::PushClipPath(const IPathPtr path, UINT mode, bool doAntiAlias /*= false*/)
	{
		const SPath_SkiaPtr path2 = std::dynamic_pointer_cast<SPath_Skia>(path);
		m_SkCanvas->clipPath(path2->m_skPath,SRegion_Skia::RGNMODE2SkRgnOP(mode),doAntiAlias);
		return S_OK;
	}

	HRESULT SRenderTarget_Skia::DrawPath(const IPathPtr path, IPathEffectPtr pathEffect)
	{
		const SPath_SkiaPtr path2 = std::dynamic_pointer_cast<SPath_Skia>(path);

		SkPaint paint=m_paint;
		paint.setColor(SColor(m_curPen->GetColor()).toARGB());
		SLineDashEffect skDash(m_curPen->GetStyle());
		paint.setPathEffect(skDash.Get());
		SStrokeCap strokeCap(m_curPen->GetStyle());
		paint.setStrokeCap(strokeCap.Get());
		SStrokeJoin strokeJoin(m_curPen->GetStyle());
		paint.setStrokeJoin(strokeJoin.Get());
		paint.setStyle(SkPaint::kStroke_Style);
		if(m_bAntiAlias)
		{
			paint.setStrokeWidth((SkScalar)m_curPen->GetWidth()-0.5f);
		}else
		{
			paint.setStrokeWidth((SkScalar)m_curPen->GetWidth());
		}

		if(pathEffect!=NULL)
		{
			SkPathEffect * skPathEffect = (SkPathEffect*)pathEffect->GetRealPathEffect();
			paint.setPathEffect(skPathEffect);
		}
		SkPath skPath;
		path2->m_skPath.offset(m_ptOrg.fX,m_ptOrg.fY,&skPath);
		m_SkCanvas->drawPath(skPath,paint);

		return S_OK;
	}

	HRESULT SRenderTarget_Skia::FillPath(const IPathPtr path)
	{
		const SPath_SkiaPtr path2 = std::dynamic_pointer_cast<SPath_Skia>(path);

		SkPaint paint=m_paint;

		if(m_curBrush->IsBitmap())
		{
			paint.setFilterBitmap(true);
			paint.setShader(SkShader::CreateBitmapShader(m_curBrush->GetBitmap(),SkShader::kRepeat_TileMode,SkShader::kRepeat_TileMode))->unref();
		}else
		{
			paint.setFilterBitmap(false);
			paint.setColor(m_curBrush->GetColor());
		}
		paint.setStyle(SkPaint::kFill_Style);

		SkPath skPath;
		path2->m_skPath.offset(m_ptOrg.fX,m_ptOrg.fY,&skPath);
		m_SkCanvas->drawPath(skPath,paint);

		return S_OK;
	}

	HRESULT SRenderTarget_Skia::PushLayer(const RECT * pRect,BYTE byAlpha)
	{
		int nLayerId = -1;
		SkRect skBound = toSkRect(pRect);
		if(byAlpha==0xFF)
			nLayerId = m_SkCanvas->saveLayer(&skBound,NULL);
		else
			nLayerId = m_SkCanvas->saveLayerAlpha(&skBound,byAlpha);
		m_lstLayerId.push_back(nLayerId);
		return S_OK;
	}

	HRESULT SRenderTarget_Skia::PopLayer()
	{
		if(m_lstLayerId.empty())
			return E_INVALIDARG;
		int nLayerID = m_lstLayerId.back();
		m_lstLayerId.pop_back();
		m_SkCanvas->restoreToCount(nLayerID);
		return S_OK;
	}

	HRESULT SRenderTarget_Skia::SetXfermode(int mode,int *pOldMode/* =NULL */)
	{
		if(pOldMode) *pOldMode = m_xferMode;
		m_xferMode = mode;
		SetPaintXferMode(m_paint,m_xferMode);
		return S_OK;
	}

	bool SRenderTarget_Skia::SetPaintXferMode(SkPaint & paint,int nRopMode)
	{
		bool bRet = true;
		switch(nRopMode)
		{
		case kSrcCopy:
			paint.setXfermodeMode(SkXfermode::kSrc_Mode);
			break;
		case kDstInvert:
			paint.setXfermode(new ProcXfermode(ProcXfermode::Rop2_Invert));
			break;
		case kSrcInvert:
			paint.setXfermode(new ProcXfermode(ProcXfermode::Rop2_Xor));
			break;
		case kSrcAnd:
			paint.setXfermode(new ProcXfermode(ProcXfermode::Rop2_And));
			break;
		default:
			if(nRopMode >= kClear_Mode && nRopMode<=kLuminosity_Mode)
				paint.setXfermodeMode((SkXfermode::Mode)nRopMode);
			else
				bRet = false;
			break;
		}
		return bRet;
	}

	BOOL SRenderTarget_Skia::SetAntiAlias(BOOL bAntilias)
	{
		BOOL bRet = m_bAntiAlias;
		m_bAntiAlias = !!bAntilias;
		m_paint.setAntiAlias(m_bAntiAlias);
		return bRet;
	}


	COLORREF SRenderTarget_Skia::GetTextColor()
	{
		return m_curColor.toCOLORREF();
	}

	COLORREF SRenderTarget_Skia::SetTextColor(COLORREF color)
	{
		COLORREF crOld=m_curColor.toCOLORREF();
		m_curColor.setRGB(color);
		m_paint.setColor(m_curColor.toARGB());
		return crOld;
	}

	IMaskFilterPtr SRenderTarget_Skia::GetMaskFilter()
	{
		return m_curMaskFilter;
	}

	void SRenderTarget_Skia::SetMaskFilter(IMaskFilterPtr pMaskFilter)
	{
		m_curMaskFilter = pMaskFilter;
		SMaskFilter_SkiaPtr pMaskFilter2 = std::dynamic_pointer_cast<SMaskFilter_Skia>(pMaskFilter);
		if(pMaskFilter2)
		{
			m_paint.setMaskFilter(pMaskFilter2->m_maskFilter);
		}
		else
		{
			m_paint.setMaskFilter(NULL);
		}
	}

    //////////////////////////////////////////////////////////////////////////
	// SBitmap_Skia
    static int s_cBmp = 0;
    SBitmap_Skia::SBitmap_Skia( IRenderFactoryPtr pRenderFac ) :IBitmap(pRenderFac),m_hBmp(0)
    {
//         STRACE(L"bitmap new; objects = %d",++s_cBmp);
    }

    SBitmap_Skia::~SBitmap_Skia()
    {
        m_bitmap.reset();
        if(m_hBmp) DeleteObject(m_hBmp);
//         STRACE(L"bitmap delete objects = %d",--s_cBmp);
    }

    HBITMAP SBitmap_Skia::CreateGDIBitmap( int nWid,int nHei,void ** ppBits )
    {
        BITMAPINFO bmi;
        memset(&bmi, 0, sizeof(bmi));
        bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
        bmi.bmiHeader.biWidth       = nWid;
        bmi.bmiHeader.biHeight      = -nHei; // top-down image 
        bmi.bmiHeader.biPlanes      = 1;
        bmi.bmiHeader.biBitCount    = 32;
        bmi.bmiHeader.biCompression = BI_RGB;
        bmi.bmiHeader.biSizeImage   = 0;

        HDC hdc=GetDC(NULL);
        //LPVOID pBits=NULL;
        HBITMAP hBmp=CreateDIBSection(hdc,&bmi,DIB_RGB_COLORS,ppBits,0,0);
        ReleaseDC(NULL,hdc);
        return hBmp;
    }

	HRESULT SBitmap_Skia::Init( int nWid,int nHei ,const LPVOID pBits/*=NULL*/)
	{
		m_bitmap.reset();
		m_bitmap.setInfo(SkImageInfo::Make(nWid,nHei,kN32_SkColorType,kPremul_SkAlphaType));
        if(m_hBmp) DeleteObject(m_hBmp);
    		
		LPVOID pBmpBits=NULL;
		m_hBmp=CreateGDIBitmap(nWid,nHei,&pBmpBits);
		if(!m_hBmp) return E_OUTOFMEMORY;
        if(pBits)
        {
            memcpy(pBmpBits,pBits,nWid*nHei*4);
        }else
        {
            memset(pBmpBits,0,nWid*nHei*4);
        }
		m_bitmap.setPixels(pBmpBits);
		return S_OK;
	}

    HRESULT SBitmap_Skia::Init( IImgFramePtr pFrame )
    {
        UINT uWid=0,uHei =0;
        pFrame->GetSize(&uWid,&uHei);

        if(m_hBmp) DeleteObject(m_hBmp);
        m_bitmap.reset();
        m_bitmap.setInfo(SkImageInfo::Make(uWid, uHei,kN32_SkColorType,kPremul_SkAlphaType));
        void * pBits=NULL;
        m_hBmp = CreateGDIBitmap(uWid,uHei,&pBits);

        if(!m_hBmp) return E_OUTOFMEMORY;
        m_bitmap.setPixels(pBits);

        const int stride = m_bitmap.rowBytes();
        pFrame->CopyPixels(NULL, stride, stride * uHei,
            reinterpret_cast<BYTE*>(m_bitmap.getPixels()));
        return S_OK;
    }

	HRESULT SBitmap_Skia::LoadFromFile( LPCTSTR pszFileName)
	{
	    IImgXPtr imgDecoder;
	    GetRenderFactory()->GetImgDecoderFactory()->CreateImgX(imgDecoder);
		if(imgDecoder->LoadFromFile(pszFileName)==0) return S_FALSE;
		return ImgFromDecoder(imgDecoder);
	}

	HRESULT SBitmap_Skia::LoadFromMemory(LPBYTE pBuf,size_t szLen)
	{
        IImgXPtr imgDecoder;
        GetRenderFactory()->GetImgDecoderFactory()->CreateImgX(imgDecoder);
		if(imgDecoder->LoadFromMemory(pBuf,szLen)==0) return S_FALSE;
        return ImgFromDecoder(imgDecoder);
	}

    HRESULT SBitmap_Skia::ImgFromDecoder(IImgXPtr imgDecoder)
    {
        IImgFrame *pFrame=imgDecoder->GetFrame(0);
        UINT uWid=0,uHei =0;
        pFrame->GetSize(&uWid,&uHei);

        if(m_hBmp) DeleteObject(m_hBmp);
        m_bitmap.reset();
        m_bitmap.setInfo(SkImageInfo::Make(uWid, uHei,kN32_SkColorType,kPremul_SkAlphaType));
        void * pBits=NULL;
        m_hBmp = CreateGDIBitmap(uWid,uHei,&pBits);
        
        if(!m_hBmp) return E_OUTOFMEMORY;
        m_bitmap.setPixels(pBits);
        
        const int stride = m_bitmap.rowBytes();
        pFrame->CopyPixels(NULL, stride, stride * uHei,
            reinterpret_cast<BYTE*>(m_bitmap.getPixels()));
        return S_OK;
    }

    UINT SBitmap_Skia::Width()  const
    {
        return m_bitmap.width();
    }

    UINT SBitmap_Skia::Height() const
    {
        return m_bitmap.height();
    }

    SIZE SBitmap_Skia::Size() const
    {
        SIZE sz={m_bitmap.width(),m_bitmap.height()};
        return sz;
    }

    LPVOID SBitmap_Skia::LockPixelBits()
    {
        return m_bitmap.getPixels();
    }

    void SBitmap_Skia::UnlockPixelBits( LPVOID pBuf)
    {
		BITMAP bm;
		GetObject(m_hBmp,sizeof(bm),&bm);
		memcpy(bm.bmBits,pBuf,Width()*Height()*4);
		m_bitmap.setPixels(pBuf);
    }

    const LPVOID SBitmap_Skia::GetPixelBits() const
    {
        return m_bitmap.getPixels();
    }

    //////////////////////////////////////////////////////////////////////////
    static int s_cRgn =0;
	SRegion_Skia::SRegion_Skia( IRenderFactoryPtr pRenderFac )
        :IRegion(pRenderFac)
	{
//         STRACE(L"region new; objects = %d",++s_cRgn);
	}

    SRegion_Skia::~SRegion_Skia()
    {
//         STRACE(L"region delete; objects = %d",--s_cRgn);
    }

	void SRegion_Skia::CombineRect( LPCRECT lprect,int nCombineMode )
	{
        m_rgn.op(toSkIRect(lprect),RGNMODE2SkRgnOP(nCombineMode));
	}

	void SRegion_Skia::CombineRoundRect(LPCRECT lprect, POINT ptRadius, int nCombineMode)
	{
		SkPath skPath;
		skPath.addRoundRect(toSkRect(lprect),SkScalar(ptRadius.x),SkScalar(ptRadius.y));
		SkRegion clip;
		clip.setRect(lprect->left,lprect->top,lprect->right,lprect->bottom);
		SkRegion rgn;
		rgn.setPath(skPath,clip);

		m_rgn.op(rgn,RGNMODE2SkRgnOP(nCombineMode));
	}

	void SRegion_Skia::CombineEllipse(LPCRECT lprect , int nCombineMode)
	{
		SkPath skPath;
		skPath.addOval(toSkRect(lprect));
		SkRegion clip;
		clip.setRect(lprect->left,lprect->top,lprect->right,lprect->bottom);
		SkRegion rgn;
		rgn.setPath(skPath,clip);

		m_rgn.op(rgn,RGNMODE2SkRgnOP(nCombineMode));
	}

	void SRegion_Skia::CombinePolygon(const POINT * pts, int count, int nPolygonMode, int nCombineMode)
	{
		SkPoint *spts = new SkPoint[count];
		RECT rc = { 0 };
		for (int i = 0; i < count; i++)
		{
			if (rc.left > pts[i].x) rc.left = pts[i].x;
			if (rc.right < pts[i].x) rc.right = pts[i].x;
			if (rc.top > pts[i].y) rc.top = pts[i].y;
			if (rc.bottom < pts[i].y) rc.bottom = pts[i].y;
			spts[i].iset(pts[i].x, pts[i].y);
		}
		SkPath skPath;
		skPath.addPoly(spts, count, true);
		delete[]spts;

		SkRegion clip;
		clip.setRect(rc.left, rc.top, rc.right, rc.bottom);
		SkRegion rgn;
		rgn.setPath(skPath, clip);

		m_rgn.op(rgn, RGNMODE2SkRgnOP(nCombineMode));

	}

    void SRegion_Skia::CombineRgn(const IRegionPtr pRgnSrc,int nCombineMode)
    {
        const SRegion_SkiaPtr pRgnSrc2 = std::dynamic_pointer_cast<SRegion_Skia>(pRgnSrc);
        m_rgn.op(pRgnSrc2->GetRegion(),RGNMODE2SkRgnOP(nCombineMode));
    }
    
	BOOL SRegion_Skia::PtInRegion( POINT pt ) const
	{
        return m_rgn.contains(pt.x,pt.y);
	}

	BOOL SRegion_Skia::RectInRegion( LPCRECT lprect ) const
	{
        assert(lprect);
        return m_rgn.intersects(toSkIRect(lprect));
	}

	void SRegion_Skia::GetRgnBox( LPRECT lprect ) const
	{
		assert(lprect);
        SkIRect rc=m_rgn.getBounds();
        lprect->left=rc.left();
        lprect->top=rc.top();
        lprect->right=rc.right();
        lprect->bottom=rc.bottom();
	}

	BOOL SRegion_Skia::IsEmpty() const
	{
        return m_rgn.isEmpty();
	}

	BOOL SRegion_Skia::IsEqual(const IRegionPtr testRgn) const
	{
		const SRegion_SkiaPtr pRgnTest = std::dynamic_pointer_cast<SRegion_Skia>(testRgn);
		return m_rgn == pRgnTest->m_rgn;
	}

    void SRegion_Skia::Offset( POINT pt )
    {
        m_rgn.translate(pt.x,pt.y);
    }

    SkRegion SRegion_Skia::GetRegion() const
    {
        return m_rgn;
    }

    void SRegion_Skia::SetRegion( const SkRegion & rgn )
    {
        m_rgn=rgn;
    }

    SkRegion::Op SRegion_Skia::RGNMODE2SkRgnOP( UINT mode )
    {
		SkRegion::Op op = SkRegion::kReplace_Op;
        switch(mode)
        {
        case RGN_COPY: op = SkRegion::kReplace_Op;break;
        case RGN_AND: op = SkRegion::kIntersect_Op;break;
        case RGN_OR: op = SkRegion::kUnion_Op;break;
        case RGN_DIFF: op = SkRegion::kDifference_Op;break;
        case RGN_XOR: op = SkRegion::kXOR_Op;break;
        default:assert(FALSE);break;
        }
        return op;
    }

    void SRegion_Skia::Clear()
    {
        m_rgn.setEmpty();
    }


    //////////////////////////////////////////////////////////////////////////
    // SFont_Skia

    //SStringT FindPropValue(const SStringT & strProp, const SStringT & strKey)
    //{
    //    SStringT strValue;
    //    int nPos1 = strProp.Find(strKey);
    //    if(nPos1!=-1)
    //    {
    //        nPos1+=strKey.GetLength();
    //        if(nPos1<strProp.GetLength() && strProp[nPos1]==_T(':'))
    //        {
    //            nPos1++;
    //            int nPos2=strProp.Find(_T(','),nPos1);
    //            if(nPos2==-1) nPos2=strProp.GetLength();
    //            strValue=strProp.Mid(nPos1,nPos2-nPos1);
    //        }
    //    }
    //    return strValue;
    //}

    static int s_cFont =0;
    SFont_Skia::SFont_Skia( IRenderFactoryPtr pRenderFac,const LOGFONT * plf) 
        :IFont(pRenderFac)
        ,m_skFont(NULL)
		,m_blurStyle((SkBlurStyle)-1)
		,m_blurRadius(0.0f)
		,m_blurFilter(NULL)
    {
        memcpy(&m_lf,plf,sizeof(LOGFONT));
#ifdef UNICODE
        //SStringA strFace=S_CT2A(plf->lfFaceName,CP_UTF8);
#else
		//SStringA strFace=S_CT2A(plf->lfFaceName,CP_ACP);
#endif
		BYTE style=SkTypeface::kNormal;
        if(plf->lfItalic) style |= SkTypeface::kItalic;
        if(plf->lfWeight == FW_BOLD) style |= SkTypeface::kBold;

		int nRet = WideCharToMultiByte(CP_UTF8, 0, plf->lfFaceName, wcslen(plf->lfFaceName), NULL, 0, NULL, NULL);
		char* pBuf = new char[nRet];
		WideCharToMultiByte(CP_UTF8, 0, plf->lfFaceName, wcslen(plf->lfFaceName), pBuf, nRet, NULL, NULL);
		m_skFont=SkTypeface::CreateFromName(pBuf,(SkTypeface::Style)style,plf->lfCharSet);
//         STRACE(L"font new: objects = %d", ++s_cFont);
		delete[]pBuf;
    }

    SFont_Skia::~SFont_Skia()
    {
		if(m_blurFilter) m_blurFilter->unref();
        if(m_skFont) m_skFont->unref();
//         STRACE(L"font delete: objects = %d", --s_cFont);
    }

	//void SFont_Skia::OnInitFinished(pugi::xml_node xmlNode)
	//{
	//	(xmlNode);
	//	if(m_blurStyle != -1 && m_blurRadius > 0.0f)
	//	{
	//		m_blurFilter = SkBlurMaskFilter::Create(m_blurStyle,
	//			SkBlurMask::ConvertRadiusToSigma(m_blurRadius));
	//	}
	//}

	BOOL SFont_Skia::UpdateFont(const LOGFONT *plf)
	{
		if(!m_skFont) return FALSE;

		memcpy(&m_lf,plf,sizeof(LOGFONT));

#ifdef UNICODE
		//SStringA strFace=S_CT2A(plf->lfFaceName,CP_UTF8);
#else
		//SStringA strFace=S_CT2A(plf->lfFaceName,CP_ACP);
#endif
		BYTE style=SkTypeface::kNormal;
		if(plf->lfItalic) style |= SkTypeface::kItalic;
		if(plf->lfWeight == FW_BOLD) style |= SkTypeface::kBold;
		m_skFont->unref();
		int nRet = WideCharToMultiByte(CP_UTF8, 0, plf->lfFaceName, wcslen(plf->lfFaceName), NULL, 0, NULL, NULL);
		char* pBuf = new char[nRet];
		WideCharToMultiByte(CP_UTF8, 0, plf->lfFaceName, wcslen(plf->lfFaceName), pBuf, nRet, NULL, NULL);
		m_skFont=SkTypeface::CreateFromName(pBuf,(SkTypeface::Style)style);
		delete[]pBuf;

		return TRUE;
	}

	namespace RENDER_SKIA
    {
        BOOL SCreateInstance(IRenderFactoryPtr& ppRenderFactory )
        {
            ppRenderFactory = std::make_shared< SRenderFactory_Skia>();
            return TRUE;
        }
    }


	//////////////////////////////////////////////////////////////////////////
	static int s_cPath =0;
	SPath_Skia::SPath_Skia(IRenderFactoryPtr pRenderFac)
		:IPath(pRenderFac)
	{
//         STRACE(L"path new; objects = %d",++s_cPath);
	}

	SPath_Skia::~SPath_Skia()
	{
//         STRACE(L"path delete; objects = %d",--s_cPath);

	}

	const OBJTYPE SPath_Skia::ObjectType() const
	{
		return OT_PATH;
	}

	IPath::FillType SPath_Skia::getFillType() const
	{
		return (IPath::FillType)m_skPath.getFillType();
	}

	void SPath_Skia::setFillType(IPath::FillType ft)
	{
		m_skPath.setFillType((SkPath::FillType)ft);
	}

	bool SPath_Skia::isInverseFillType() const
	{
		return m_skPath.isInverseFillType();
	}

	void SPath_Skia::toggleInverseFillType()
	{
		m_skPath.toggleInverseFillType();
	}

	IPath::Convexity SPath_Skia::getConvexity() const
	{
		return (IPath::Convexity)m_skPath.getConvexity();
	}

	void SPath_Skia::setConvexity(Convexity c)
	{
		m_skPath.setConvexity((SkPath::Convexity)c);
	}

	bool SPath_Skia::isConvex() const
	{
		return m_skPath.isConvex();
	}

	bool SPath_Skia::isOval(RECT* rect) const
	{
		SkRect skRect;
		bool bRet = m_skPath.isOval(&skRect);
		if(rect && bRet)
		{
			SkRect2RECT(skRect,rect);
		}
		return bRet;
	}

	void SPath_Skia::reset()
	{
		m_skPath.reset();
	}

	void SPath_Skia::rewind()
	{
		m_skPath.rewind();
	}

	bool SPath_Skia::isEmpty() const
	{
		return m_skPath.isEmpty();
	}

	bool SPath_Skia::isFinite() const
	{
		return m_skPath.isFinite();
	}

	bool SPath_Skia::isLine(POINT line[2]) const
	{
		SkPoint skLine[2];
		bool bRet = m_skPath.isLine(skLine);
		if(bRet)
		{
			line[0].x = (int)skLine[0].fX;
			line[0].y = (int)skLine[0].fY;
			line[1].x = (int)skLine[1].fX;
			line[1].x = (int)skLine[1].fY;
		}
		return bRet;
	}

	bool SPath_Skia::isRect(RECT* rect) const
	{
		SkRect skRect;
		bool bRet = m_skPath.isRect(&skRect);
		if(rect && bRet)
		{
			SkRect2RECT(skRect,rect);
		}
		return bRet;
	}

	bool SPath_Skia::isRect(bool* isClosed, Direction* direction) const
	{
		return m_skPath.isRect(isClosed,(SkPath::Direction*)direction);
	}

	int SPath_Skia::countPoints() const
	{
		return m_skPath.countPoints();
	}

	fPoint SPath_Skia::getPoint(int index) const
	{
		SkPoint ret = m_skPath.getPoint(index);
		fPoint pt = {ret.fX,ret.fY};
		return pt;
	}

	int SPath_Skia::getPoints(fPoint points[], int max) const
	{
		assert(points);
		SkPoint *pts = new SkPoint[max];
		int nRet = m_skPath.getPoints(pts,max);
		for(int i=0;i<nRet;i++)
		{
			points[i].fX = pts[i].fX;
			points[i].fY = pts[i].fY;
		}
		delete []pts;
		return nRet;
	}

	int SPath_Skia::countVerbs() const
	{
		return m_skPath.countVerbs();
	}

	int SPath_Skia::getVerbs(BYTE verbs[], int max) const
	{
		return m_skPath.getVerbs(verbs,max);
	}

	RECT SPath_Skia::getBounds() const
	{
		const SkRect &rc = m_skPath.getBounds();
		RECT rcRet;
		SkRect2RECT(rc,&rcRet);
		return rcRet;
	}

	void SPath_Skia::moveTo(float x, float y)
	{
		m_skPath.moveTo(x,y);
	}

	void SPath_Skia::rMoveTo(float dx, float dy)
	{
		m_skPath.rMoveTo(dx,dy);
	}

	void SPath_Skia::lineTo(float x, float y)
	{
		m_skPath.lineTo(x,y);
	}

	void SPath_Skia::rLineTo(float dx, float dy)
	{
		m_skPath.rLineTo(dx,dy);
	}

	void SPath_Skia::quadTo(float x1, float y1, float x2, float y2)
	{
		m_skPath.quadTo(x1,y1,x2,y2);
	}

	void SPath_Skia::rQuadTo(float dx1, float dy1, float dx2, float dy2)
	{
		m_skPath.rQuadTo(dx1,dy1,dx2,dy2);
	}

	void SPath_Skia::conicTo(float x1, float y1, float x2, float y2, float w)
	{
		m_skPath.conicTo(x1,y1,x2,y2,w);
	}

	void SPath_Skia::rConicTo(float dx1, float dy1, float dx2, float dy2, float w)
	{
		m_skPath.rConicTo(dx1,dy1,dx2,dy2,w);
	}

	void SPath_Skia::cubicTo(float x1, float y1, float x2, float y2, float x3, float y3)
	{
		m_skPath.cubicTo(x1,y1,x2,y2,x3,y3);
	}

	void SPath_Skia::rCubicTo(float dx1, float dy1, float dx2, float dy2, float dx3, float dy3)
	{
		m_skPath.rCubicTo(dx1,dy1,dx2,dy2,dx3,dy3);
	}

	void SPath_Skia::arcTo(const RECT& oval, float startAngle, float sweepAngle, bool forceMoveTo)
	{
		SkRect skOval = toSkRect(&oval);
		m_skPath.arcTo(skOval,startAngle,sweepAngle,forceMoveTo);
	}

	void SPath_Skia::arcTo(float x1, float y1, float x2, float y2, float radius)
	{
		m_skPath.arcTo(x1,y1,x2,y2,radius);
	}

	void SPath_Skia::close()
	{
		m_skPath.close();
	}

	void SPath_Skia::addRect(const RECT& rect, Direction dir /*= kCW_Direction*/)
	{
		SkRect skRc = toSkRect(&rect);
		m_skPath.addRect(skRc,(SkPath::Direction)dir);
	}

	void SPath_Skia::addRect(float left, float top, float right, float bottom, Direction dir /*= kCW_Direction*/)
	{
		m_skPath.addRect(left,top,right,bottom,(SkPath::Direction)dir);
	}

	void SPath_Skia::addOval(const RECT& oval, Direction dir /*= kCW_Direction*/)
	{
		SkRect skRc = toSkRect(&oval);
		m_skPath.addOval(skRc,(SkPath::Direction)dir);
	}

	void SPath_Skia::addCircle(float x, float y, float radius, Direction dir /*= kCW_Direction*/)
	{
		m_skPath.addCircle(x,y,radius,(SkPath::Direction)dir);
	}

	void SPath_Skia::addArc(const RECT& oval, float startAngle, float sweepAngle)
	{
		SkRect skRc = toSkRect(&oval);
		m_skPath.addArc(skRc,startAngle,sweepAngle);
	}

	void SPath_Skia::addRoundRect(const RECT& rect, float rx, float ry, Direction dir /*= kCW_Direction*/)
	{
		SkRect skRc = toSkRect(&rect);
		m_skPath.addRoundRect(skRc,rx,ry,(SkPath::Direction)dir);
	}

	void SPath_Skia::addRoundRect(const RECT& rect, const float radii[], Direction dir /*= kCW_Direction*/)
	{
		SkRect skRc = toSkRect(&rect);
		m_skPath.addRoundRect(skRc,radii,(SkPath::Direction)dir);
	}

	void SPath_Skia::addPoly(const POINT pts[], int count, bool close)
	{
		SkPoint *skPts = new SkPoint[count];
		for(int i=0;i<count;i++)
		{
			skPts[i].fX = (float)pts[i].x;
			skPts[i].fY = (float)pts[i].y;
		}

		m_skPath.addPoly(skPts,count,close);
		delete []skPts;
	}

	void SPath_Skia::addPath(const IPath * src, float dx, float dy, AddPathMode mode /*= kAppend_AddPathMode*/)
	{
		const SPath_Skia *skSrc = (const SPath_Skia*)src;
		m_skPath.addPath(skSrc->m_skPath,dx,dy,(SkPath::AddPathMode)mode);
	}

	void SPath_Skia::reverseAddPath(const IPath* src)
	{
		const SPath_Skia *skSrc = (const SPath_Skia*)src;
		m_skPath.reverseAddPath(skSrc->m_skPath);
	}

	void SPath_Skia::offset(float dx, float dy)
	{
		m_skPath.offset(dx,dy);
	}

	void SPath_Skia::transform(const IxForm * xForm)
	{
		SkMatrix mat;
		mat.setAll(xForm->GetValue(IxForm::kMScaleX),
			xForm->GetValue(IxForm::kMSkewX), 
			xForm->GetValue(IxForm::kMTransX),
			xForm->GetValue(IxForm::kMSkewY),
			xForm->GetValue(IxForm::kMScaleY), 
			xForm->GetValue(IxForm::kMTransY),
			xForm->GetValue(IxForm::kMPersp0), 
			xForm->GetValue(IxForm::kMPersp1), 
			xForm->GetValue(IxForm::kMPersp2));
		m_skPath.transform(mat);
	}

	bool SPath_Skia::getLastPt(POINT* lastPt) const
	{
		SkPoint pt;
		bool bRet = m_skPath.getLastPt(&pt);
		if(lastPt)
		{
			lastPt->x = (int)pt.fX;
			lastPt->y = (int)pt.fY;
		}
		return bRet;
	}

	void SPath_Skia::setLastPt(float x, float y)
	{
		m_skPath.setLastPt(x,y);
	}

	void SPath_Skia::addString(LPCTSTR pszText,int nLen, float x,float y, const IFont *pFont)
	{
		const SFont_Skia *pFontSkia = (const SFont_Skia *)pFont;
		if(nLen < 0) nLen = _tcslen(pszText);
		SkPaint paint;
		paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
		paint.setTypeface(pFontSkia->GetFont());
		const LOGFONT *plf = pFont->LogFont();
		paint.setTextSize(SkIntToScalar(abs(plf->lfHeight)));
		paint.setUnderlineText(!!plf->lfUnderline);
		paint.setStrikeThruText(!!plf->lfStrikeOut);

		SkPath path;
#ifdef _UNICODE
		paint.getTextPath(pszText,nLen,0.0f,0.0f,&path);
#else
		SStringW str=S_CT2W(SStringT(pszText,nLen));
		paint.getTextPath((LPCWSTR)str,str.GetLength(),0.0f,0.0f,&path);
#endif
		m_skPath.addPath(path,x,y,SkPath::kAppend_AddPathMode);
	}

	static void addLine(std::vector<SkPoint>& segmentPoints, std::vector<float>& lengths,
		const SkPoint& toPoint) {
		if (segmentPoints.empty()) {
			segmentPoints.push_back(SkPoint::Make(0, 0));
			lengths.push_back(0);
		}
		else if (segmentPoints.back() == toPoint) {
			return; // Empty line
		}
		float length = lengths.back() + SkPoint::Distance(segmentPoints.back(), toPoint);
		segmentPoints.push_back(toPoint);
		lengths.push_back(length);
	}
	typedef SkPoint(*bezierCalculation)(float t, const SkPoint* points);


	static float cubicCoordinateCalculation(float t, float p0, float p1, float p2, float p3) {
		float oneMinusT = 1 - t;
		float oneMinusTSquared = oneMinusT * oneMinusT;
		float oneMinusTCubed = oneMinusTSquared * oneMinusT;
		float tSquared = t * t;
		float tCubed = tSquared * t;
		return (oneMinusTCubed * p0) + (3 * oneMinusTSquared * t * p1)
			+ (3 * oneMinusT * tSquared * p2) + (tCubed * p3);
	}

	static SkPoint cubicBezierCalculation(float t, const SkPoint* points) {
		float x = cubicCoordinateCalculation(t, points[0].x(), points[1].x(),
			points[2].x(), points[3].x());
		float y = cubicCoordinateCalculation(t, points[0].y(), points[1].y(),
			points[2].y(), points[3].y());
		return SkPoint::Make(x, y);
	}

	static float quadraticCoordinateCalculation(float t, float p0, float p1, float p2) {
		float oneMinusT = 1 - t;
		return oneMinusT * ((oneMinusT * p0) + (t * p1)) + t * ((oneMinusT * p1) + (t * p2));
	}

	static SkPoint quadraticBezierCalculation(float t, const SkPoint* points) {
		float x = quadraticCoordinateCalculation(t, points[0].x(), points[1].x(), points[2].x());
		float y = quadraticCoordinateCalculation(t, points[0].y(), points[1].y(), points[2].y());
		return SkPoint::Make(x, y);
	}

	// Subdivide a section of the Bezier curve, set the mid-point and the mid-t value.
	// Returns true if further subdivision is necessary as defined by errorSquared.
	static bool subdividePoints(const SkPoint* points, bezierCalculation bezierFunction,
		float t0, const SkPoint &p0, float t1, const SkPoint &p1,
		float& midT, SkPoint &midPoint, float errorSquared) {
		midT = (t1 + t0) / 2;
		float midX = (p1.x() + p0.x()) / 2;
		float midY = (p1.y() + p0.y()) / 2;

		midPoint = (*bezierFunction)(midT, points);
		float xError = midPoint.x() - midX;
		float yError = midPoint.y() - midY;
		float midErrorSquared = (xError * xError) + (yError * yError);
		return midErrorSquared > errorSquared;
	}

	static void addBezier(const SkPoint* points,
		bezierCalculation bezierFunction, std::vector<SkPoint>& segmentPoints,
		std::vector<float>& lengths, float errorSquared, bool doubleCheckDivision) {
		typedef std::map<float, SkPoint> PointMap;
		PointMap tToPoint;

		tToPoint[0] = (*bezierFunction)(0, points);
		tToPoint[1] = (*bezierFunction)(1, points);

		PointMap::iterator iter = tToPoint.begin();
		PointMap::iterator next = iter;
		++next;
		while (next != tToPoint.end()) {
			bool needsSubdivision = true;
			SkPoint midPoint;
			do {
				float midT;
				needsSubdivision = subdividePoints(points, bezierFunction, iter->first,
					iter->second, next->first, next->second, midT, midPoint, errorSquared);
				if (!needsSubdivision && doubleCheckDivision) {
					SkPoint quarterPoint;
					float quarterT;
					needsSubdivision = subdividePoints(points, bezierFunction, iter->first,
						iter->second, midT, midPoint, quarterT, quarterPoint, errorSquared);
					if (needsSubdivision) {
						// Found an inflection point. No need to double-check.
						doubleCheckDivision = false;
					}
				}
				if (needsSubdivision) {
					next = tToPoint.insert(iter, PointMap::value_type(midT, midPoint));
				}
			} while (needsSubdivision);
			iter = next;
			next++;
		}

		// Now that each division can use linear interpolation with less than the allowed error
		for (iter = tToPoint.begin(); iter != tToPoint.end(); ++iter) {
			addLine(segmentPoints, lengths, iter->second);
		}
	}

	static void addMove(std::vector<SkPoint>& segmentPoints, std::vector<float>& lengths,
		const SkPoint& point) {
		float length = 0;
		if (!lengths.empty()) {
			length = lengths.back();
		}
		segmentPoints.push_back(point);
		lengths.push_back(length);
	}

	static void createVerbSegments(SkPath::Verb verb, const SkPoint* points,
		std::vector<SkPoint>& segmentPoints, std::vector<float>& lengths, float errorSquared) {
		switch (verb) {
		case SkPath::kMove_Verb:
			addMove(segmentPoints, lengths, points[0]);
			break;
		case SkPath::kClose_Verb:
			addLine(segmentPoints, lengths, points[0]);
			break;
		case SkPath::kLine_Verb:
			addLine(segmentPoints, lengths, points[1]);
			break;
		case SkPath::kQuad_Verb:
			addBezier(points, quadraticBezierCalculation, segmentPoints, lengths,
				errorSquared, false);
			break;
		case SkPath::kCubic_Verb:
			addBezier(points, cubicBezierCalculation, segmentPoints, lengths,
				errorSquared, true);
			break;
		default:
			// Leave element as NULL, Conic sections are not supported.
			break;
		}
	}

	IPathInfo* SPath_Skia::approximate(float acceptableError)
	{
		SkPath::Iter pathIter(m_skPath, false);
		SkPath::Verb verb;
		SkPoint points[4];
		std::vector<SkPoint> segmentPoints;
		std::vector<float> lengths;
		float errorSquared = acceptableError * acceptableError;

		while ((verb = pathIter.next(points, false)) != SkPath::kDone_Verb) {
			createVerbSegments(verb, points, segmentPoints, lengths, errorSquared);
		}

		if (segmentPoints.empty()) {
			int numVerbs = m_skPath.countVerbs();
			if (numVerbs == 1) {
				addMove(segmentPoints, lengths, m_skPath.getPoint(0));
			}
			else {
				// Invalid or empty path. Fall back to point(0,0)
				addMove(segmentPoints, lengths, SkPoint());
			}
		}

		float totalLength = lengths.back();
		if (totalLength == 0) {
			// Lone Move instructions should still be able to animate at the same value.
			segmentPoints.push_back(segmentPoints.back());
			lengths.push_back(1);
			totalLength = 1;
		}

		size_t numPoints = segmentPoints.size();
		size_t approximationArraySize = numPoints * 3;

		int nLen = approximationArraySize;

		SPathInfo_Skia * pInfo = new SPathInfo_Skia(numPoints);
		float* approximation = pInfo->buffer();

		int approximationIndex = 0;
		for (size_t i = 0; i < numPoints; i++) {
			const SkPoint& point = segmentPoints[i];
			approximation[approximationIndex++] = lengths[i] / totalLength;
			approximation[approximationIndex++] = point.x();
			approximation[approximationIndex++] = point.y();
		}

		return pInfo;
	}

	SPathInfo_Skia::SPathInfo_Skia(int points):mPoints(points),mData(new float[points*3])
	{
		
	}

	SPathInfo_Skia::~SPathInfo_Skia()
	{
		delete []mData;
	}

	int SPathInfo_Skia::pointNumber() const
	{
		return mPoints;
	}

	const float * SPathInfo_Skia::data() const
	{
		return mData;
	}

	float * SPathInfo_Skia::buffer()
	{
		return mData;
	}

//--------------------------------------------------------------------------------
	SMaskFilter_Skia::SMaskFilter_Skia(SkMaskFilter *maskFilter):m_maskFilter(maskFilter)
	{
	}

	SMaskFilter_Skia::~SMaskFilter_Skia()
	{
		if(m_maskFilter)
		{
			m_maskFilter->unref();
		}
	}
}//end of namespace SOUI

